/*
 *  Brno University of Technology
 *
 *  Copyright (C) 2009-2010 by Brno University of Technology and the contributors
 *
 *  Complete list of developers available at our web site:
 *
 *       http://spl.utko.feec.vutbr.cz
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
 */
package cz.vutbr.feec.utko.ef.ga;

import java.util.Collection;
import java.util.Vector;

import org.apache.log4j.Logger;

import cz.vutbr.feec.utko.ef.evolution.Chromozome;

/**
 * The Class GeneticAlgorithmChromozome is used be genetic algorithm and uses
 * uniform crossover.
 */
public class GAUniformChromozome extends Chromozome {

	private static final long serialVersionUID = 2031903194621328289L;

	/** The gene. */
	protected Vector<GAGene> genes = new Vector<GAGene>();

	/** The log. */
	transient private static Logger log = Logger
			.getLogger(GAUniformChromozome.class);

	/**
	 * Instantiates a new genetic algorithm chromozome.
	 */
	public GAUniformChromozome() {

	}

	/**
	 * Instantiates a new genetic algorithm chromozome.
	 * 
	 * @param genes
	 *            the chromozome
	 */
	public GAUniformChromozome(GAGene[] genes) {
		for (GAGene g : genes) {
			this.genes.add(g.cloneDeep());
		}
		// mutate all
		mutateAll();
	}

	public GAUniformChromozome(GAUniformChromozome template) {
		for (GAGene g : template.getGenes()) {
			this.genes.add(g.cloneDeep());
		}
		// mutate all
		mutateAll();
	}

	/**
	 * Adds the.
	 * 
	 * @param in
	 *            the gene
	 */
	public void add(GAGene in) {
		this.genes.add(in);
	}

	/* (non-Javadoc)
	 * @see cz.vutbr.feec.utko.ef.evolution.Chromozome#cloneDeep()
	 */
	public GAUniformChromozome cloneDeep() {
		try {
			// clone chromozome
			GAUniformChromozome newChromozome;
			newChromozome = (GAUniformChromozome) this.clone();

			return newChromozome;

		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Crossover.
	 * 
	 * @param ch
	 *            the chromozome
	 * @param type
	 *            the crossover type
	 */
	@Override
	public void crossover(Chromozome ch) {
		GAUniformChromozome gau = (GAUniformChromozome) ch;

		GAGene helper;
		for (int i = 0; i < this.genes.size(); i = i + 2) {
			helper = this.genes.get(i);
			this.genes.set(i, gau.genes.get(i));
			gau.genes.set(i, helper);
		}
		resetCachedFitness();
		//this.evaluateFitness();*/
	}

	

	/**
	 * Gets the individuals.
	 * 
	 * @return the individuals
	 */
	public GAGene getGene(int index) {
		return this.genes.get(index);
	}

	/* (non-Javadoc)
	 * @see cz.vutbr.feec.utko.ef.evolution.Chromozome#getResult()
	 */
	@Override
	public Object getResult() {
		return genes;
	}

	/**
	 * Mutate.
	 */
	public void mutate() {
		GAGene g = genes.get((int) (Math.random() * genes.size()));
		g.randomInit();
		resetCachedFitness();
		//this.evaluateFitness();
	}

	/**
	 * Mutate all.
	 */
	protected void mutateAll() {
		for (GAGene g : genes) {
			g.randomInit();
		}
		resetCachedFitness();
	}

	/**
	 * Removes the.
	 * 
	 * @param index
	 *            the index
	 */
	public void remove(int index) {
		this.genes.remove(index);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {

		StringBuilder completeChromozome = new StringBuilder();

		completeChromozome.append("----- Chromozome -----\n\n");

		for (GAGene gen : this.genes) {
			completeChromozome.append(gen.toString() + "\n");
		}
		completeChromozome.append("FITNESS:"+getCachedFitness());
		
		return completeChromozome.toString();
	}

	/* (non-Javadoc)
	 * @see cz.vutbr.feec.utko.ef.evolution.Chromozome#validate()
	 */
	public void validate() {
		log.warn("Validation is not yet implemented for this class");
	}

	/**
	 * Adds the vector gen.
	 * 
	 * @param cloneBusinessProcessDNAGEN the clone business process dnagen
	 */
	public void addVectorGen(Vector<GAGene> cloneBusinessProcessDNAGEN) {
		for (GAGene gaGene : cloneBusinessProcessDNAGEN) {
			this.add(gaGene);
		}
		
	}

	/**
	 * Clear all.
	 */
	public void clearAll() {
		genes.clear();
		
	}


	/**
	 * Gets the genes.
	 * 
	 * @return the genes
	 */
	public Collection<GAGene> getGenes() {
		return genes;
	}

}
